package com.minivision.fdiot.mqtt;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;

import org.apache.commons.io.FileUtils;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttPersistenceException;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.minivision.fdiot.mqtt.message.UpgradeFile;
import com.minivision.fdiot.mqtt.protocol.Packet;
import com.minivision.fdiot.mqtt.protocol.Packet.Head;
import com.minivision.fdiot.mqtt.protocol.Packet.Head.CmdCode;
import com.minivision.fdiot.mqtt.protocol.Packet.Head.Type;
import com.minivision.fdiot.mqtt.protocol.PacketUtils;
import com.minivision.fdiot.mqtt.protocol.SecurityUtil;

public class MqttSimulator {
  
  public static final String HOST = "tcp://localhost:1883";
  
  private static final ObjectMapper MAPPER = new ObjectMapper();

  private static final String sn = "test";
  private static final String model = "box";

  private MqttClient client;
  private String userName = sn;
  private String passWord = model + "::" + sn;


  public MqttSimulator() throws MqttException {
    client = new MqttClient(HOST, sn, new MemoryPersistence());
    connect();
  }

  private void connect() {
    MqttConnectOptions options = new MqttConnectOptions();
    options.setAutomaticReconnect(true);
    options.setCleanSession(true);
    options.setUserName(userName);
    SecurityUtil passwordUtil = new SecurityUtil("SHA-256", "minivision");
    options.setPassword(passwordUtil.encode(passWord).toCharArray());
    options.setConnectionTimeout(10);
    options.setKeepAliveInterval(10);
    
    try {
      client.setCallback(new MqttCallback() {
        @Override
        public void messageArrived(String topic, MqttMessage message)
            throws Exception {
          System.out.println("receive a message on : "+ topic);
          ByteBuffer buffer = ByteBuffer.wrap(message.getPayload());
          PacketUtils packetUtils = new PacketUtils();
          Head head = packetUtils.parseHead(buffer);
          int code = head.getCode();
          buffer.position(PacketUtils.BIN_HEAD_LEN);
          
          byte[] bodyBytes = new byte[buffer.remaining()];
          buffer.get(bodyBytes);
          if (code == Packet.Head.CmdCode.UPGRADE_FILE) {
            UpgradeFile fileData = new UpgradeFile();
            fileData.decode(bodyBytes);
            System.out.println(fileData.getFunc());
            FileUtils.writeByteArrayToFile(new File("F:\\sample.png"), fileData.getFile());
          }
          
          /*Packet<?> packet = MAPPER.readValue(message.getPayload(), Packet.class);
          System.out.println("packet : "+ packet.toString());
          Head head = packet.getHead();*/
          
          if(head.getType() == Type.REQUEST){
            head.setType(Type.RESPONSE_OK);
            Packet<Void> rePacket = new Packet<>();
            rePacket.setHead(head);
            publishObject("/s/" + model, rePacket);
          }
        }
        @Override
        public void deliveryComplete(IMqttDeliveryToken token) {
          System.out.println("deliveryComplete : messageId = "+ token.getMessageId());
        }
        @Override
        public void connectionLost(Throwable paramThrowable) {
          System.out.println("connection lost:" + paramThrowable);
        }
      });
      client.connect(options);
      client.subscribe("/d/" + model + "/" + sn);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public void publish(String topic, MqttMessage message)
      throws MqttPersistenceException, MqttException {
    client.publish(topic, message);
  }
  
  public void publishObject(String topic, Object object)
      throws MqttPersistenceException, MqttException, JsonProcessingException {
    MqttMessage message = new MqttMessage();
    message.setPayload(MAPPER.writeValueAsBytes(object));
    client.publish(topic, message);
  }
  
  public static void main(String[] args) throws MqttException, IOException, InterruptedException {
    MqttSimulator simulator = new MqttSimulator();
    /*Head head = new Head(10000, 107, Type.REQUEST);
    Packet<?> packet = new Packet<>(head);
    simulator.publishObject("/s/pad", packet);*/
    /*Status status = new Status();
    status.setCpu(33.33f);
    status.setMem(44.44f);
    status.setTimestamp(new Date());*/
    
    //Head head = new Head(10000, 5, Type.REQUEST);
    /*Person person = new Person();
    person.setName("hugh");
    Address address = new Address();
    address.setCity("nj");
    address.setLongitude(118.78);
    address.setLatitude(32.04);
    person.setAddress(address);
    List<String> list = new ArrayList<>();
    list.add("test");
    person.setList(list);
    Map<String, String> map = new LinkedHashMap<>();
    map.put("key", "value");
    person.setMap(map);
    Map<String, Address> addressMap = new LinkedHashMap<>();
    addressMap.put("nj", address);
    person.setAddressMap(addressMap);
    person.setImage(FileUtils.readFileToByteArray(new File("F:\\待完成的工作-1.png")));
    
    List<Person> persons = new ArrayList<>();
    persons.add(person);
    
    Society society = new Society();
    society.setPersons(persons);
    SocietyMessage body = new SocietyMessage();
    body.setData(society);*/
    /*AddressBookMessage body = new AddressBookMessage();
    AddressBookProtos.AddressBook.Builder bookBuilder = AddressBookProtos.AddressBook.newBuilder();
    AddressBookProtos.PersonInfo.Builder personBuilder = AddressBookProtos.PersonInfo.newBuilder();
    AddressBookProtos.PersonInfo.PhoneNumber.Builder phoneBuilder = AddressBookProtos.PersonInfo.PhoneNumber.newBuilder();
    phoneBuilder.setType(PhoneType.MOBILE);
    phoneBuilder.setNumber("13510438684");
    personBuilder.setName("hugh");
    personBuilder.setId(100000);
    personBuilder.setEmail("hugh282003@163.com");
    personBuilder.addPhones(phoneBuilder.build());
    personBuilder.setImg(ByteString.copyFrom(FileUtils.readFileToByteArray(new File("F:\\待完成的工作-1.png"))));
    bookBuilder.addPeople(personBuilder.build());
    body.setData(bookBuilder.build());
    Packet<?> packet = new Packet<>(head, body);
    PacketUtils packetUtils = new PacketUtils();
    byte[] bs = packetUtils.serialize(packet);
    MqttMessage message = new MqttMessage(bs);
    simulator.publish("/sb/" + model, message);*/
    //Packet<?> packet = new Packet<>(head, status);
    //simulator.publishObject("/s/pad", packet);
    
    //byte[] bs = FileUtils.readFileToByteArray(new File("E://9000001.jpg"));
    //MqttMessage message = new MqttMessage(bs);
    //simulator.publish("/s", message);
    
    /*BinaryStatus bStatus = new BinaryStatus();
    
    bStatus.setCpu(33.33f);
    bStatus.setMem(44.44f);
    bStatus.setTimestamp(new Date());
    bStatus.setImgBytes(FileUtils.readFileToByteArray(new File("F:\\待完成的工作-2.png")));
    
    Packet<?> bpacket = new Packet<>(head, bStatus);
    PacketUtils packetUtils = new PacketUtils();
    byte[] bs = packetUtils.serialize(bpacket);
    
    Head parseHead = packetUtils.parseHead(ByteBuffer.wrap(bs));
    System.out.println(parseHead);
    MqttMessage message = new MqttMessage(bs);
    simulator.publish("/sb/pad", message);*/
    
    /*Head downloadHead = new Head(10000, CmdCode.FACESET_DOWNLOAD, Type.REQUEST);
    DownloadReq req = new DownloadReq();
    req.setFacesetToken("95077c4d-fc0a-465c-9310-87f0f6d21811");
    Packet<?> downloadPacket = new Packet<>(downloadHead, req);
    simulator.publishObject("/s/" + model, downloadPacket);*/
    
    Head head = new Head(10000, CmdCode.CONNECT, Type.NOTIFY);
    Packet<?> packet = new Packet<>(head);
    simulator.publishObject("/s/" + model, packet);
  }
}
